/*
 * @Description:
 * @Version:
 * @Author: Troubadour
 * @Date: 2023-02-02 13:51:23
 * @LastEditors: Troubadour 2276791354@qq.com
 * @LastEditTime: 2024-08-02 00:27:32
 */

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Include file                                                                       -
--------------------------------------------------------------------------------------------------------------------------------------*/
#include "ina226_obj.h"
#include "FreeRTOS.h"
#include "task.h"

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal macro                                                                     -
--------------------------------------------------------------------------------------------------------------------------------------*/

#define INA226_Delay_Ms(ms)     vTaskDelay(pdMS_TO_TICKS(ms))
#define INA226_CFG_REG 0x00  /* 配置寄存器 */
#define INA226_SV_REG 0x01   // 分流电压
#define INA226_BV_REG 0x02   // 总线电压
#define INA226_PWR_REG 0x03  // 电源功率
#define INA226_CUR_REG 0x04  // 电流
#define INA226_CAL_REG 0x05  // 校准，设定满量程范围以及电流和功率测数的
#define INA226_ONFF_REG 0x06 // 屏蔽 使能 警报配置和转换准备就绪
#define INA226_AL_REG 0x07   // 包含与所选警报功能相比较的限定值
#define INA226_GET_ADDR 0XFF // 包含唯一的芯片标识号
#define INA226_ADDR1 0x80
// #define   INA226_GETALADDR    0x14

#define INA226_SHUNT_VOLTAGE_LSB (2.5)         // 分流电压 LSB 2.5uV
#define INA226_VBUS_Voltage_LSB (1.25)         // 总线电压 LSB 1.25mV
/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal enum                                                                      -
--------------------------------------------------------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal structure                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal function                                                                  -
--------------------------------------------------------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Internal variables                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/

static uint8_t INA226_Obj_SendData(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t addr, uint8_t reg, uint16_t data);
static uint8_t INA226_Obj_ReadData(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t addr, uint8_t reg, uint16_t *readData);

/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  External variables                                                                 -
--------------------------------------------------------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------------------------------------------------------
-                                                  Function body                                                                      -
--------------------------------------------------------------------------------------------------------------------------------------*/

/**
 * @function: INA226_Obj_SendData
 * @brief: This function is used to send data to the register.
 * @param {SoftAnalogIIC_Typedef} *pIIC_Struct: IIC Struct.
 * @param {uint8_t} addr: The address of the module.
 * @param {uint8_t} reg: The address of the register.
 * @param {uint16_t} data: The data to be sent.
 * @return {uint8_t} return 0: success, 1: fail.
 */
static uint8_t INA226_Obj_SendData(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t addr, uint8_t reg, uint16_t data)
{
    SoftAnalogIIC_Start(pIIC_Struct);

    SoftAnalogIIC_Send_Byte(pIIC_Struct, addr);
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;

    SoftAnalogIIC_Send_Byte(pIIC_Struct, reg);
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;

    SoftAnalogIIC_Send_Byte(pIIC_Struct, (uint8_t)(data >> 8));
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;

    SoftAnalogIIC_Send_Byte(pIIC_Struct, (uint8_t)(data & 0x00FF));
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;
    SoftAnalogIIC_Stop(pIIC_Struct);
    return 0;
}

/**
 * @function: INA226_Obj_ReadData
 * @brief: This function is used to read data from the register.
 * @param {SoftAnalogIIC_Typedef} *pIIC_Struct: IIC Struct.
 * @param {uint8_t} addr: The address of the module.
 * @param {uint8_t} reg: The address of the register.
 * @param {uint16_t} *readData: The data to be read.
 * @return {uint8_t} return 0: success, 1: fail.
 */
static uint8_t INA226_Obj_ReadData(SoftAnalogIIC_Typedef *pIIC_Struct, uint8_t addr, uint8_t reg, uint16_t *readData)
{
    if (readData == NULL) return 1;

    SoftAnalogIIC_Start(pIIC_Struct);
    SoftAnalogIIC_Send_Byte(pIIC_Struct, addr);
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;

    SoftAnalogIIC_Send_Byte(pIIC_Struct, reg);
    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;
    SoftAnalogIIC_Stop(pIIC_Struct);
    /* Restart the IIC bus. */
    SoftAnalogIIC_Start(pIIC_Struct);
    SoftAnalogIIC_Send_Byte(pIIC_Struct, addr + 1);

    if (SoftAnalogIIC_Wait_Ack(pIIC_Struct) != IIC_OK)  return 1;
    *readData = SoftAnalogIIC_Read_Byte(pIIC_Struct, 1);

    *readData <<= 8;
    *readData |= SoftAnalogIIC_Read_Byte(pIIC_Struct, 0);
    SoftAnalogIIC_Stop(pIIC_Struct);
    return 0;
}

/**
 * @function: INA226_Obj_Get_ID
 * @brief: This function is used to get the ID of the module.
 * @param {INA226TypeDef} *pIna226: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Get_ID(INA226TypeDef *pIna226)
{
    return INA226_Obj_ReadData(pIna226->pIIC_Struct, pIna226->addr, INA226_GET_ADDR, &pIna226->id);
}

/**
 * @function: INA226_Obj_Get_Current
 * @brief: This function is used to get the current of the module.
 * @param {INA226TypeDef} *pIna226: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Get_Current(INA226TypeDef *pIna226)
{
    uint16_t readData = 0;

    if (INA226_Obj_ReadData(pIna226->pIIC_Struct, pIna226->addr, INA226_CUR_REG, &readData) != 0)
    {
        return 1;
    }
    if (readData & 0x8000)
    {
        readData = ~(readData - 1);
    }
    pIna226->current = (double)readData * pIna226->current_lsb;
    return 0;
}

/**
 * @function: INA226_Obj_Get_VbusVoltage
 * @brief This function is used to get the VBUS voltage of the module.
 * @param {INA226TypeDef} *pIna226: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Get_VbusVoltage(INA226TypeDef *pIna226)
{
    uint16_t readData = 0;

    if (INA226_Obj_ReadData(pIna226->pIIC_Struct, pIna226->addr, INA226_BV_REG, &readData) != 0)
    {
        return 1;
    }
    pIna226->voltage = (double)readData * INA226_VBUS_Voltage_LSB / 1000.0;
    return 0;
}

/**
 * @function: INA226_Obj_Get_ShuntVoltage
 * @brief This function is used to get the shunt voltage of the module.
 * @param {INA226TypeDef} *pIna226: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Get_ShuntVoltage(INA226TypeDef *pIna226)
{
    uint16_t readData = 0;

    if (INA226_Obj_ReadData(pIna226->pIIC_Struct, pIna226->addr, INA226_SV_REG, &readData) != 0)
    {
        return 1;
    }
    if (readData & 0x8000)
    {
        readData = ~(readData - 1);
    }
    pIna226->shuntVoltage = (double)readData * INA226_SHUNT_VOLTAGE_LSB;
    return 0;
}

/**
 * @function: INA226_Obj_Get_PowerIns
 * @brief This function is used to get the power of the module.
 * @param {INA226TypeDef} *pIna226: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Get_PowerIns(INA226TypeDef *pIna226)
{
    uint16_t readData = 0;

    pIna226->power = pIna226->voltage * pIna226->current;
    if (INA226_Obj_ReadData(pIna226->pIIC_Struct, pIna226->addr, INA226_SV_REG, &readData) != 0)
    {
        return 1;
    }
    pIna226->power_ins = (double)readData * 25.0 * pIna226->current_lsb;
    return 0;
}

/**
 * @function: INA226_Obj_Init
 * @brief This function is used to initialize the IIC. Must to be configured before using.
 * 1. Configure the SCL and SDA pins from SoftAnalogIIC struct.
 * 2. Configure the conversion time, the average number of times, the sampling time, and the mode. By the 'Cfg_register'.
 * 3. Configure the calibration value. By the 'Calibration_value'.
 * @param {INA226TypeDef} *ina226_struct: The struct of the INA226.
 * @return {uint8_t} return 0: success, 1: fail.
 */
uint8_t INA226_Obj_Init(INA226TypeDef *ina226_struct)
{
    /* Initialize the IIC. */
    SoftAnalogIIC_Init(ina226_struct->pIIC_Struct);
    /* Restart the INA226. */
    INA226_Obj_SendData(ina226_struct->pIIC_Struct, ina226_struct->addr, INA226_CFG_REG, 0x8000);
    INA226_Delay_Ms(100);
    /* Set the conversion time, the average number of times, the sampling time, and the mode. */
    INA226_Obj_SendData(ina226_struct->pIIC_Struct, ina226_struct->addr, INA226_CFG_REG, ina226_struct->Cfg_register);
    INA226_Obj_SendData(ina226_struct->pIIC_Struct, ina226_struct->addr, INA226_CAL_REG, ina226_struct->Calibration_value);
    /* Get the ID. */
    return INA226_Obj_Get_ID(ina226_struct);
}


